package cn.iocoder.yudao.module.erp.service.stocksmove;

import cn.iocoder.yudao.module.erp.common.InventoryTurnover;
import cn.iocoder.yudao.module.erp.dal.dataobject.pristock.PriStockDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.secaccount.SecAccountDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.secstock.SecStockDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.warehouseinlist.WarehouseInListDO;
import cn.iocoder.yudao.module.erp.dal.mysql.pristock.PriStockMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.secaccount.SecAccountMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.secstock.SecStockMapper;
import cn.iocoder.yudao.module.erp.service.secstock.SecStockService;
import cn.iocoder.yudao.module.erp.service.secstock.SecStockServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import cn.iocoder.yudao.module.erp.controller.admin.stocksmove.vo.*;
import cn.iocoder.yudao.module.erp.dal.dataobject.stocksmove.StocksMoveDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stocksmoveitem.StocksMoveItemDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.erp.dal.mysql.stocksmove.StocksMoveMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.stocksmoveitem.StocksMoveItemMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*;

/**
 * ERP 库存调拨单 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
public class StocksMoveServiceImpl implements StocksMoveService {

    @Resource
    private StocksMoveMapper stocksMoveMapper;
    @Resource
    private StocksMoveItemMapper stocksMoveItemMapper;
    @Resource
    private ErpProductMapper erpProductMapper;
    @Resource
    private SecStockMapper  secStockMapper;
    @Resource
    private PriStockMapper priStockMapper;
    @Resource
    private InventoryTurnover inventoryTurnover;
    @Resource
    private SecAccountMapper secAccountMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createStocksMove(StocksMoveSaveReqVO createReqVO) {
        // 插入
        StocksMoveDO stocksMove = BeanUtils.toBean(createReqVO, StocksMoveDO.class);
        stocksMoveMapper.insert(stocksMove);

        // 插入子表
        createStocksMoveItemList(stocksMove.getId(), createReqVO.getStocksMoveItems());
        // 返回
        return stocksMove.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStocksMove(StocksMoveSaveReqVO updateReqVO) {
        // 校验存在
        validateStocksMoveExists(updateReqVO.getId());
        // 更新
        StocksMoveDO updateObj = BeanUtils.toBean(updateReqVO, StocksMoveDO.class);
        stocksMoveMapper.updateById(updateObj);

        // 更新子表
        updateStocksMoveItemList(updateReqVO.getId(), updateReqVO.getStocksMoveItems());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteStocksMove(Long id) {
        // 校验存在
        validateStocksMoveExists(id);
        // 删除
        stocksMoveMapper.deleteById(id);

        // 删除子表
        deleteStocksMoveItemByMoveId(id);
    }

    private void validateStocksMoveExists(Long id) {
        if (stocksMoveMapper.selectById(id) == null) {
            throw exception(STOCKS_MOVE_NOT_EXISTS);
        }
    }

    @Override
    public StocksMoveDO getStocksMove(Long id) {
        return stocksMoveMapper.selectById(id);
    }

    @Override
    public PageResult<StocksMoveDO> getStocksMovePage(StocksMovePageReqVO pageReqVO) {
        return stocksMoveMapper.selectPage(pageReqVO);
    }

    // ==================== 子表（ERP 库存调拨项） ====================

    @Override
    public List<StocksMoveItemDO> getStocksMoveItemListByMoveId(Long moveId) {
        List<StocksMoveItemDO> stocksMoveItemDOS = stocksMoveItemMapper.selectListByMoveId(moveId);
//        给stocksMoveItemDOS设置 产品名 单位名
        List<Long> productIds = stocksMoveItemDOS.stream().map(StocksMoveItemDO::getProductId).collect(Collectors.toList());
        List<ErpProductDO> erpProductDOS = erpProductMapper.selectList(new QueryWrapper<ErpProductDO>().in("id", productIds));
        Map<Long, ErpProductDO> productDOMap = erpProductDOS.stream().collect(Collectors.toMap(ErpProductDO::getId, ErpProductDO -> ErpProductDO));
        stocksMoveItemDOS.forEach(stocksMoveItemDO -> {
            stocksMoveItemDO.setProductName(productDOMap.get(stocksMoveItemDO.getProductId()).getName());
            stocksMoveItemDO.setProductUnitName(productDOMap.get(stocksMoveItemDO.getProductId()).getUnitName());
        });
        return stocksMoveItemDOS;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createStocksOnMoveItem(StocksMoveSaveReqVO createReqVO) {
//        先根据 产品Id 产品批次 入库批次 查二级库存 如果有这个产品就修改其库存  没有就新增
        List<StocksMoveItemDO> stocksMoveItems = createReqVO.getStocksMoveItems();
//        入库科室
        Long toWarehouseId = createReqVO.getToWarehouseId();
        Long fromWarehouseId = createReqVO.getFromWarehouseId(); //出库科室
        List<SecStockQueryKey> queryKeys = new ArrayList<>();
        Map<SecStockQueryKey, StocksMoveItemDO> itemMap = new HashMap<>();

//        根据 productId 和 入库批次 查询一级库存
        List<Long> productIds = stocksMoveItems.stream().map(StocksMoveItemDO::getProductId).collect(Collectors.toList());
        List<PriStockDO> priStockDOS = priStockMapper.selectList(new QueryWrapper<PriStockDO>().in("product_id", productIds));
//        Map<Long, PriStockDO> priStockDOMap = priStockDOS.stream().collect(Collectors.toMap(PriStockDO::getProductId, PriStockDO -> PriStockDO));
        Map<Long, PriStockDO> priStockDOMap = priStockDOS.stream()
                .collect(Collectors.toMap(
                        PriStockDO::getProductId,
                        priStockDO -> priStockDO,
                        (existing, replacement) -> existing // 如果存在重复 key，保留第一个出现的对象
                ));
        for (StocksMoveItemDO item : stocksMoveItems) {
            SecStockQueryKey key = new SecStockQueryKey(
                    item.getProductId(),
                    toWarehouseId,
                    item.getProductBatch(),
                    item.getInboundBatch()
            );
            queryKeys.add(key);
            itemMap.put(key, item); // 保存映射关系
        }

        // 2. 批量查询已存在的 SecStockDO 记录
        List<SecStockDO> existingList = secStockMapper.selectByBatchIds(queryKeys);

        // 3. 构建需要更新和新增的列表
        List<SecStockDO> updateList = new ArrayList<>();
        List<SecStockDO> insertList = new ArrayList<>();
        //        要插入台账的集合
        List<SecAccountDO> secAccountlist = new ArrayList<>();
        //            生成入库单数据   返回出库单编号
        WarehouseInListDO warehouseInListDO = new WarehouseInListDO()
                .setInDeptId(String.valueOf(toWarehouseId))
                .setOutDeptId(String.valueOf(fromWarehouseId))
                .setInTime(LocalDateTime.now());
        String inAffairsId = inventoryTurnover.creatWarehouseInList(warehouseInListDO);

        // 4. 分离出哪些是需要更新的，哪些是需要新增的
        Map<Long, SecStockDO> existingMap = existingList.stream()
                .collect(Collectors.toMap(SecStockDO::getProductId, s -> s));

        for (StocksMoveItemDO key : stocksMoveItems) {
            Long productId = key.getProductId();
            BigDecimal count = key.getCount();

            if (existingMap.containsKey(productId)) {
                // 存在则更新库存数量
                SecStockDO stock = existingMap.get(productId);
                stock.setCount(stock.getCount().add(count));

//                二级库台账数据
                SecAccountDO inSecAccountDO = getInSecAccountDO(count, stock, toWarehouseId,fromWarehouseId, inAffairsId);
                secAccountlist.add(inSecAccountDO);
                updateList.add(stock);

            } else {
                // 不存在则新增
                SecStockDO newStock = new SecStockDO();
                PriStockDO priStockDO = priStockDOMap.get(productId);
//                BeanUtils.copyProperties(priStockDO, newStock);
                newStock.setCount(count)
                        .setProductId(productId)
                        .setProductStandards(priStockDO.getProductStandards())
                        .setDeptId(toWarehouseId)
                        .setProductBatch(key.getProductBatch())
                        .setProductPrice(priStockDO.getProductPrice())
                        .setProductUnitId(priStockDO.getProductUnitId())
                        .setProductUnitName(priStockDO.getProductUnitName())
                        .setProductName(priStockDO.getProductName())
                        .setProductCategoryId(priStockDO.getProductCategoryId())
                        .setProductCategoryName(priStockDO.getProductCategoryName())
                        .setProductValidityDate(priStockDO.getProductValidityDate())
                        .setInboundBatch(key.getInboundBatch());
                //                二级库台账数据
                SecAccountDO inSecAccountDO = getInSecAccountDO(count, newStock, toWarehouseId,fromWarehouseId, inAffairsId);
                secAccountlist.add(inSecAccountDO);
                insertList.add(newStock);
            }
        }

        // 5. 批量更新和新增
        if (!updateList.isEmpty()) {
//            secStockMapper.updateBatch(updateList);
            secStockMapper.updateBatchIgnoreVersion(updateList);
        }
        if (!insertList.isEmpty()) {
            secStockMapper.insertBatch(insertList);
        }
        if (!secAccountlist.isEmpty()) {
            secAccountMapper.insertBatch(secAccountlist);
        }

    }
    /**
     * 生成台账信息的方法（入库）
     * @param count     核销数
     * @param secStockDO
     * @return
     */
    public SecAccountDO getInSecAccountDO(BigDecimal count, SecStockDO secStockDO, Long toWarehouseId,Long fromWarehouseId, String AffairsId) {
        // 处理插入二级库台账的数据
        SecAccountDO secAccountDO = new SecAccountDO();
        BeanUtils.copyProperties(secStockDO, secAccountDO);
        secAccountDO.setAffairs("入库")
                .setAffairsId(AffairsId) // 使用常量或枚举
                .setDeptId(fromWarehouseId)
                .setToDeptId(toWarehouseId)
                .setFromDeptId(fromWarehouseId)
                .setRemark("库存加" + count)
                .setCount(count)
                .setStatus(1) // 使用常量或枚举
                .setId(null).setCreateTime(LocalDateTime.now())
                .setUpdateTime(null);
        return secAccountDO;
    }

    private void createStocksMoveItemList(Long moveId, List<StocksMoveItemDO> list) {
        list.forEach(o -> o.setMoveId(moveId));
        stocksMoveItemMapper.insertBatch(list);
    }

    private void updateStocksMoveItemList(Long moveId, List<StocksMoveItemDO> list) {
        deleteStocksMoveItemByMoveId(moveId);
        list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下：1）id 冲突；2）updateTime 不更新
        createStocksMoveItemList(moveId, list);
    }

    private void deleteStocksMoveItemByMoveId(Long moveId) {
        stocksMoveItemMapper.deleteByMoveId(moveId);
    }

}